package com.xzcs.util.net;

import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.cookie.CookieSpecProvider;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;

/**
 * httpClient帮助类
 * @author chang
 * @createDate 2015-01-21
 */
public class HttpClientUtils {
	public static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
	private String encode = "UTF-8";
	private static HttpHost proxy;
	private static CredentialsProvider credsProvider;
	
	public HttpClientUtils(){
	
	}
	public HttpClientUtils(String encode){
		this.encode = encode;
	}

	private static X509TrustManager tm = new X509TrustManager() {
		public void checkClientTrusted(X509Certificate[] xcs, String string) 
				throws CertificateException {
			
		}

		public void checkServerTrusted(X509Certificate[] xcs, String string) 
				throws CertificateException {
			
		}

		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}
	};

	/**
	 * 初始HttpClient对象 如果是https自动下载证书
	 * @return
	 */
	public static CloseableHttpClient getHttpClient() {
		//可关闭的HttpClient  
		CloseableHttpClient closeableHttpClient;
		SSLContext sslContext = null;
		try {
			sslContext = SSLContext.getInstance("TLS");
			sslContext.init(null, new TrustManager[] {tm}, null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
		
		//设置全局cookie策略
		RequestConfig config = RequestConfig.custom().setConnectTimeout(15000)
				.setSocketTimeout(15000).setCookieSpec(CookieSpecs.STANDARD_STRICT)
				.setProxy(proxy).build();
		closeableHttpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
				.setUserAgent("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)")
				.setDefaultCredentialsProvider(credsProvider)
				.setDefaultRequestConfig(config).build();
        
        return closeableHttpClient;
	}
	
	/**
	 * 设置代理
	 * @param host 主机
	 * @param port 端口
	 * @param scheme 代理类型  http/https
	 * @param userName 用户名
	 * @param pwd  密码
	 */
	public void setHttpProxy(String host, int port, String scheme, String userName, String pwd){
		proxy = new HttpHost(host, port, scheme);
		
		if (null != userName && null != pwd) {
			credsProvider = new BasicCredentialsProvider();
	        credsProvider.setCredentials(new AuthScope(host, port),//可以访问的范围
	                new UsernamePasswordCredentials(userName, pwd));//用户名和密码
		}
	}

	/**
	 * 打印提交参数
	 * @param params
	 */
	public void printParams(List<NameValuePair> params) {
		// 输出相关提交参数
		String p = "";
		for (NameValuePair n : params) {
			p += n.getName() + " => " + n.getValue() + " \n";
		}
		logger.debug("params is : \n" + p);
	}

	/**
	 * 打印请求头
	 * @param headers
	 */
	public void printHeader(HeaderIterator headers) {
		HeaderIterator its = headers;
		while (its.hasNext()) {
			logger.debug("请求头:" + its.next());
		}
	}

	/**
	 * 打印响应头
	 * @param headers
	 */
	public void printHeader(Header[] headers) {
		for (int i = 0; i < headers.length; i++) {
			logger.debug("header = " + headers[i].getName() + " , value = " + headers[i].getValue());
		}
	}
	
	public String getCookieStr(Map<String, String> cookieMap){
		String cookieStr = "";
		if (null != cookieMap) {
			for (Map.Entry<String, String> entry : cookieMap.entrySet()) {
				cookieStr += "; " + entry.getKey() + "=" + entry.getValue();
			}
		}
		if (cookieStr.length() > 0) {
			cookieStr = cookieStr.substring(2);
		}
		//logger.debug("cookieStr:"+cookieStr);
		return cookieStr;
	}

	/**
	 * 创建post请求
	 * @param url
	 * @return HttpPost
	 */
	public HttpPost getHttpPost(String url, Map<String, String> cookieMap) {
		// 创建post请求
		HttpPost post = new HttpPost(url);
		String cookieStr = getCookieStr(cookieMap);
		post.addHeader("Cookie", cookieStr);
		return post;
	}

	/**
	 * 创建get请求
	 * @param url
	 * @return HttpGet
	 */
	public HttpGet getHttpGet(String url, Map<String, String> cookieMap) {
		// 创建get请求
		HttpGet get = new HttpGet(url);
		String cookieStr = getCookieStr(cookieMap);
		get.addHeader("Cookie", cookieStr);
		return get;
	}
	
	public HttpPut getHttpPut(String url, Map<String, String> cookieMap) {
		// 创建put请求
		HttpPut put = new HttpPut(url);
		String cookieStr = getCookieStr(cookieMap);
		put.addHeader("Cookie", cookieStr);
		return put;
	}
	
	public HttpDelete getHttpDelete(String url, Map<String, String> cookieMap) {
		// 创建delete请求
		HttpDelete delete = new HttpDelete(url);
		String cookieStr = getCookieStr(cookieMap);
		delete.addHeader("Cookie", cookieStr);
		return delete;
	}

	/**
	 * 设置请求头
	 * @param headerMap
	 * @param get
	 */
	public void setHeader(Map<String, String> headerMap, HttpGet get) {
		if (null != headerMap) {
			for (Map.Entry<String, String> c : headerMap.entrySet()) {
				get.setHeader(c.getKey(), c.getValue());
			}
		}
	}

	/**
	 * 设置请求头
	 * @param headerMap
	 * @param post
	 */
	public void setHeader(Map<String, String> headerMap, HttpPost post) {
		if (null != headerMap) {
			for (Map.Entry<String, String> c : headerMap.entrySet()) {
				post.setHeader(c.getKey(), c.getValue());
			}
		}
	}
	
	public void setHeader(Map<String, String> headerMap, HttpPut put) {
		if (null != headerMap) {
			for (Map.Entry<String, String> c : headerMap.entrySet()) {
				put.setHeader(c.getKey(), c.getValue());
			}
		}
	}
	
	public void setHeader(Map<String, String> headerMap, HttpDelete delete) {
		if (null != headerMap) {
			for (Map.Entry<String, String> c : headerMap.entrySet()) {
				delete.setHeader(c.getKey(), c.getValue());
			}
		}
	}

	/**
	 * 设置请求参数
	 * @param params
	 * @return
	 */
	public List<NameValuePair> setParams(Map<String, String> params) {
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		if (null != params) {
			for (Map.Entry<String, String> param : params.entrySet()) {
				parameters.add(new BasicNameValuePair(param.getKey(), param.getValue()));
			}
		}
		return parameters;
	}

	/**
	 * get请求
	 * @param url
	 * @param params
	 * @param headerMap
	 * @param cookieMap
	 * @param isGzip 返回的数据是否是gzip,deflate
	 * @return
	 */
	public String doGetRequest(String url, Map<String, String> params, Map<String, String> headerMap, 
			Map<String, String> cookieMap, boolean isGzip) {
		//logger.debug("-------------------doGetRequest start-------------------");
		CloseableHttpClient httpclient = getHttpClient();
		// 获取请求参数
		List<NameValuePair> parameters = setParams(params);
		String urlString = URLEncodedUtils.format(parameters, encode);
		if (!urlString.equals("")) {
			if (url.indexOf("?") == -1) {
				url = url + "?" + urlString;
			} else {
				url = url + "&" + urlString;
			}
		}

		//logger.debug("doGetRequest url = " + url);
		HttpGet get = getHttpGet(url, cookieMap);
		// 设置请求头
		setHeader(headerMap, get);

		String responseBody = "";
		try {
			HttpResponse response = httpclient.execute(get);
			responseBody = getResponseString(get, response, isGzip);
		} catch (Exception e) {
			logger.error("doGetRequest error : ", e);
		} finally {
			try {
				httpclient.close();
			} catch (IOException e) {
				logger.error("close error : ", e);
			}
		}
		//logger.debug("-------------------doGetRequest end-------------------");
		return responseBody;
	}

	/**
	 * post请求
	 * @param url
	 * @param params
	 * @param headerMap
	 * @param cookieMap
	 * @param isGzip 返回的数据是否是gzip,deflate
	 * @return
	 */
	public String doPostRequest(String url, Map<String, String> params, Map<String, String> headerMap, Map<String, 
			String> cookieMap, boolean isGzip) {
		//logger.debug("-------------------doPostRequest start-------------------");
		// 创建客户端
		CloseableHttpClient httpclient = getHttpClient();
		HttpPost post = getHttpPost(url, cookieMap);
		// 设置请求头
		setHeader(headerMap, post);
		// 获取请求参数
		List<NameValuePair> parameters = setParams(params);

		String responseBody = "";
		try {
			UrlEncodedFormEntity uef = new UrlEncodedFormEntity(parameters, encode);
			post.setEntity(uef);
			//logger.info("doPostRequest url = " + url + "?" + URLEncodedUtils.format(parameters, encode));
			HttpResponse response = httpclient.execute(post);
			responseBody = getResponseString(post, response, isGzip);
		} catch (Exception e) {
			logger.error("doPostRequest error:", e);
		} finally {
			try {
				httpclient.close();
			} catch (IOException e) {
				logger.error("close error:", e);
			}
		}
		//logger.debug("-------------------doPostRequest end-------------------");
		return responseBody;
	}

	/**
	 * post请求发送字符串
	 * @param url
	 * @param params
	 * @param headerMap
	 * @param cookieMap
	 * @param isGzip
     * @return
     */
	public String doPostRequest(String url, String params, Map<String, String> headerMap, Map<String,
			String> cookieMap, boolean isGzip) {
		//logger.debug("-------------------doPostRequest start-------------------");
		// 创建客户端
		CloseableHttpClient httpclient = getHttpClient();
		HttpPost post = getHttpPost(url, cookieMap);
		// 设置请求头
		setHeader(headerMap, post);

		String responseBody = "";
		try {
			StringEntity se = new StringEntity(params, encode);
			post.setEntity(se);
			HttpResponse response = httpclient.execute(post);
			responseBody = getResponseString(post, response, isGzip);
		} catch (Exception e) {
			logger.error("doPostRequest error:", e);
		} finally {
			try {
				httpclient.close();
			} catch (IOException e) {
				logger.error("close error:", e);
			}
		}
		//logger.debug("-------------------doPostRequest end-------------------");
		return responseBody;
	}
	
	public String doPutRequest(String url, Map<String, String> params, Map<String, String> headerMap, 
			Map<String, String> cookieMap, boolean isGzip) {
		//logger.debug("-------------------doPutRequest start-------------------");
		CloseableHttpClient httpclient = getHttpClient();
		// 获取请求参数
		List<NameValuePair> parameters = setParams(params);

		HttpPut put = getHttpPut(url, cookieMap);
		// 设置请求头
		setHeader(headerMap, put);

		String responseBody = "";
		try {
			UrlEncodedFormEntity uef = new UrlEncodedFormEntity(parameters, encode);
			put.setEntity(uef);
			HttpResponse response = httpclient.execute(put);
			responseBody = getResponseString(put, response, isGzip);
		} catch (Exception e) {
			logger.error("doPutRequest error : ", e);
		} finally {
			try {
				httpclient.close();
			} catch (IOException e) {
				logger.error("close error : ", e);
			}
		}
		//logger.debug("-------------------doPutRequest end-------------------");
		return responseBody;
	}
	
	public String doDeleteRequest(String url, Map<String, String> params, Map<String, String> headerMap, 
			Map<String, String> cookieMap, boolean isGzip) {
		//logger.debug("-------------------doDeleteRequest start-------------------");
		CloseableHttpClient httpclient = getHttpClient();
		// 获取请求参数
		List<NameValuePair> parameters = setParams(params);
		String urlString = URLEncodedUtils.format(parameters, encode);
		if (!urlString.equals("")) {
			if (url.indexOf("?") == -1) {
				url = url + "?" + urlString;
			} else {
				url = url + "&" + urlString;
			}
		}

		//logger.debug("doDeleteRequest url = " + url);
		HttpDelete delete = getHttpDelete(url, cookieMap);
		// 设置请求头
		setHeader(headerMap, delete);

		String responseBody = "";
		try {
			HttpResponse response = httpclient.execute(delete);
			responseBody = getResponseString(delete, response, isGzip);
		} catch (Exception e) {
			logger.error("doDeleteRequest error : ", e);
		} finally {
			try {
				httpclient.close();
			} catch (IOException e) {
				logger.error("close error : ", e);
			}
		}
		//logger.debug("-------------------doDeleteRequest end-------------------");
		return responseBody;
	}

	/**
	 * 获取cookieStore
	 * @param url
	 * @param headerMap
	 * @return
	 */
	public CookieStore getCookie(String url, Map<String, String> headerMap) {
		CloseableHttpClient httpClient = getHttpClient();
		CookieStore cookieStore = new BasicCookieStore();
		HttpGet httpGet = new HttpGet(url);
		// 设置请求头
		setHeader(headerMap, httpGet);
		HttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpGet.abort();
			} else {
				Header[] headers = response.getHeaders("Set-Cookie");
				for (int i = 0; i < headers.length; i++) {
					String value = headers[i].getValue();
					String cookieName = value.substring(0, value.indexOf("="));
					String cookieValue = value.substring(value.indexOf("=")+1, value.indexOf(";"));
					BasicClientCookie cookie = new BasicClientCookie(cookieName, cookieValue);
					cookieStore.addCookie(cookie);
				}
			}
		} catch (Exception e) {
			logger.error("postCheckCode error:", e);
		} finally {
			try {
				httpClient.close();
			} catch (IOException e) {
				logger.error("close error:", e);
			}
		}
		return cookieStore;
	}

	/**
	 * 获取httpClientContext
	 * @param url
	 * @param headerMap
	 * @return
	 */
	public HttpClientContext getContext(String url, Map<String, String> headerMap) {
		CloseableHttpClient httpClient = getHttpClient();
		HttpClientContext context = HttpClientContext.create();
		CookieStore cookieStore = new BasicCookieStore();
		HttpGet httpGet = new HttpGet(url);
		// 设置请求头
		setHeader(headerMap, httpGet);
		HttpResponse response = null;
		try {
			response = httpClient.execute(httpGet);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				httpGet.abort();
			} else {
				Header[] headers = response.getHeaders("Set-Cookie");
				for (int i = 0; i < headers.length; i++) {
					String value = headers[i].getValue();
					String cookieName = value.substring(0, value.indexOf("="));
					String cookieValue = value.substring(value.indexOf("=")+1, value.indexOf(";"));
					BasicClientCookie cookie = new BasicClientCookie(cookieName, cookieValue);
					cookieStore.addCookie(cookie);
				}
				Registry<CookieSpecProvider> registry = RegistryBuilder
					.<CookieSpecProvider>create().build();
				context.setCookieSpecRegistry(registry);
				context.setCookieStore(cookieStore);
			}
		} catch (Exception e) {
			logger.error("postCheckCode error:", e);
		} finally {
			try {
				httpClient.close();
			} catch (IOException e) {
				logger.error("close error:", e);
			}
		}
		return context;
	}

	/**
	 * 获取图片
	 * @param url
	 * @param filePath
	 * @param params
	 * @param headerMap
	 * @param cookieMap
	 * @throws Exception 
	 */
	public void getImage(String url, String filePath, Map<String, String> params, Map<String, String> headerMap, Map<String, String> cookieMap) throws Exception {
		CloseableHttpClient httpclient = getHttpClient();
		// 获取请求参数
		List<NameValuePair> parameters = setParams(params);
		String urlString = URLEncodedUtils.format(parameters, encode);
		if (url.indexOf("?") == -1) {
			url = url + "?" + urlString;
		} else {
			url = url + "&" + urlString;
		}
		logger.debug("getImage url = " + url);
		HttpGet get = getHttpGet(url, cookieMap);
		// 设置请求头
		setHeader(headerMap, get);

		try {
			HttpResponse response = httpclient.execute(get);
			int statusCode = response.getStatusLine().getStatusCode();
			if (statusCode != HttpStatus.SC_OK) {
				get.abort();
			} else {
				HttpEntity entity = response.getEntity();
				if (entity != null){
					byte[] resByte = EntityUtils.toByteArray(entity);
					BufferedOutputStream out = null;  
					if (resByte.length > 0) {  
						try {  
							out = new BufferedOutputStream(new FileOutputStream(filePath));  
							out.write(resByte);  
							out.flush();  
						} finally {  
							if (out != null)  
								out.close();  
						}  
					} 

				}
				EntityUtils.consume(entity);
			}
		} catch (Exception e) {
			throw new Exception("getImage error", e);
		} finally {
			httpclient.close();
		}
	}

	/**
	 * 获取响应字符串
	 * @param request
	 * @param response
	 * @param isGzip
     * @return
     */
	private String getResponseString(HttpRequestBase request, HttpResponse response, boolean isGzip){
		String responseBody = "";
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK) {
			request.abort();
		} else {
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null){
					if (isGzip) {
						responseBody = zipInputStream(entity.getContent());
					} else {
						responseBody = readInputStream(entity.getContent());
					}
				}
				EntityUtils.consume(entity);
			} catch (Exception e) {
				logger.error("getResponseBody error : ", e);
			}
		}
		return responseBody;
	}

	/**
	 * 处理返回文件流
	 * @param is
	 * @return
	 * @throws IOException
	 */
	private String readInputStream(InputStream is) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(is, encode));
		StringBuffer buffer = new StringBuffer();
		String line;
		while ((line = in.readLine()) != null)
			buffer.append(line + "\n");
		is.close();
		return buffer.toString();
	}

	/**
	 * 处理gzip,deflate返回流
	 * @param is
	 * @return
	 * @throws IOException
	 */
	private String zipInputStream(InputStream is) throws IOException {
		GZIPInputStream gzip = new GZIPInputStream(is);
		BufferedReader in = new BufferedReader(new InputStreamReader(gzip, encode));
		StringBuffer buffer = new StringBuffer();
		String line;
		while ((line = in.readLine()) != null)
			buffer.append(line + "\n");
		is.close();
		return buffer.toString();
	}

	public static void main(String[] args) {
		HttpClientUtils httpClient = new HttpClientUtils();
		String result = httpClient.doPostRequest("http://data.zz.baidu.com/urls?site=www.fenghuox.com&token=VZp6nOTiB5WPql6g",
				"http://www.fenghuox.com/cssofts/blog/content/39875.shtml\n" +
						"http://www.fenghuox.com/cssofts/blog/content/39890.shtml", null, null, false);
		System.out.println("result:"+result);
	}
}